package org.spamforces.utils;

import java.text.SimpleDateFormat;
import java.util.*;

public class TimeAndDateComParser {
    private static final String[] RUSSIAN_MONTH_NAMES = {"января", "февраля", "марта", "апреля", "мая", "июня", "июля", "августа", "сентября", "октября", "ноября", "декабря"};
    private static final int[] COUNT_MONTHS_DAY = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

    private static final String URL_START = "http://timeanddate.com/worldclock/fixedtime.html?";
    private static final String URL_FINISH = "&p1=166";

    private static String formatRussian(int year, int month, int day, int hour, int minute, int second) {
        Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("Europe/Moscow"));

        try {
            calendar.set(year, month, day, hour, minute, second);
        } catch (Exception e) {
            throw new IllegalArgumentException(e.getMessage());
        }

        Locale ruLocale = new Locale("ru");

        String dayOfWeek = calendar.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.LONG, ruLocale);
        SimpleDateFormat format = new SimpleDateFormat(String.format("YYYY HH:mm"), ruLocale);
        format.setTimeZone(TimeZone.getTimeZone("Europe/Moscow"));

        Date time = calendar.getTime();
        return Integer.toString(day) + " " + RUSSIAN_MONTH_NAMES[month] + " (" + dayOfWeek + "), " + format.format(time) + " (Московское время)";
    }

    private static String formatEnglish(int year, int month, int day, int hour, int minute, int second) {
        Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("Europe/Moscow"));
        try {
            calendar.set(year, month, day, hour, minute, second);
        } catch (Exception e) {
            throw new IllegalArgumentException(e.getMessage());
        }

        Locale usLocale = Locale.US;

        SimpleDateFormat format = new SimpleDateFormat(String.format("EEEE, MMMM, d, YYYY HH:mm (zzz)"), usLocale);
        format.setTimeZone(TimeZone.getTimeZone("UTC"));

        Date time = calendar.getTime();
        return format.format(time);
    }

    /**
     * Returns human-readable form of time by timeanddate.com link.
     *
     * @param timeAndDateComUrl In form like http://timeanddate.com/worldclock/fixedtime.html?day=13&month=7&year=2014&hour=17&min=0&sec=0&p1=166
     * @param language          Only "ru" or "en" are supported
     * @return Human-readable form of the given time.
     */
    public static String format(String timeAndDateComUrl, String language) {
        if (!timeAndDateComUrl.startsWith(URL_START)) {
            throw new IllegalArgumentException("Expected valid timeanddate.com URL, should start with `" + URL_START + "`.");
        }

        if (!timeAndDateComUrl.endsWith(URL_FINISH)) {
            throw new IllegalArgumentException("Expected valid timeanddate.com URL, should end with `" + URL_FINISH + "`.");
        }

        if (!language.equals("ru") && !language.equals("en")) {
            throw new IllegalArgumentException("Expected 'ru' or 'en' as language.");
        }

        String[] tokens = timeAndDateComUrl.split("[?&=]");

        int year = -1;
        int month = -1;
        int day = -1;
        int hour = -1;
        int minute = -1;
        int second = -1;

        for (int i = 0; i < tokens.length - 1; i++) {
            if (tokens[i].equals("year")) {
                year = Integer.parseInt(tokens[i + 1]);
            }

            if (tokens[i].equals("month")) {
                month = Integer.parseInt(tokens[i + 1]);
            }

            if (tokens[i].equals("day")) {
                day = Integer.parseInt(tokens[i + 1]);
            }

            if (tokens[i].equals("hour")) {
                hour = Integer.parseInt(tokens[i + 1]);
            }

            if (tokens[i].equals("min")) {
                minute = Integer.parseInt(tokens[i + 1]);
            }

            if (tokens[i].equals("sec")) {
                second = Integer.parseInt(tokens[i + 1]);
            }
        }

        month--;

        if (year == -1 || month == -1 || day == -1 || hour == -1 || minute == -1 || second == -1) {
            throw new IllegalArgumentException(String.format(
                    "Expected valid timeanddate.com URL: year=%d, month=%d, day=%d, hour=%d, minute=%d, second=%d.",
                    year,
                    month + 1,
                    day,
                    hour,
                    minute,
                    second
            ));
        }

        if (year < 0 || month < 0 || month >= 12) {
            throw new IllegalArgumentException(String.format(
                    "Incorrect data in timeanddate.com URL: year=%d, month=%d, day=%d, hour=%d, minute=%d, second=%d.",
                    year,
                    month + 1,
                    day,
                    hour,
                    minute,
                    second
            ));
        }

        boolean isLeapYear = false;
        if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
            isLeapYear = true;
        }

        if (month == 1 && isLeapYear) {
            if (day < 1 || day > 29) {
                throw new IllegalArgumentException(String.format(
                        "Incorrect data in timeanddate.com URL: year=%d, month=%d, day=%d, hour=%d, minute=%d, second=%d.",
                        year,
                        month + 1,
                        day,
                        hour,
                        minute,
                        second
                ));
            }
        } else {
            if (day < 1 || day > COUNT_MONTHS_DAY[month]) {
                throw new IllegalArgumentException(String.format(
                        "Incorrect data in timeanddate.com URL: year=%d, month=%d, day=%d, hour=%d, minute=%d, second=%d.",
                        year,
                        month + 1,
                        day,
                        hour,
                        minute,
                        second
                ));
            }
        }

        if (hour < 0 || hour >= 24 || minute < 0 || minute >= 60 || second < 0 || second >= 60) {
            throw new IllegalArgumentException(String.format(
                    "Incorrect data in timeanddate.com URL: year=%d, month=%d, day=%d, hour=%d, minute=%d, second=%d.",
                    year,
                    month + 1,
                    day,
                    hour,
                    minute,
                    second
            ));
        }

        if (language.equals("ru")) {
            try {
                return formatRussian(year, month, day, hour, minute, second);
            } catch (IllegalArgumentException e) {
                throw new IllegalArgumentException(e.getMessage());
            }
        }

        if (language.equals("en")) {
            try {
                return formatEnglish(year, month, day, hour, minute, second);
            } catch (IllegalArgumentException e) {
                throw new IllegalArgumentException(e.getMessage());
            }
        }

        throw new RuntimeException("Unexpected case: language=" + language + ".");
    }
}

